/*
 *  Project:            Gateway_TSN_CAN.
 *  Module name:        Gateway_top.
 *  Description:        Top Module of Gateway_top.
 *  Last updated date:  2023.03.14.
 *
 *  Communication with Junnan Li <lijunnan@nudt.edu.cn>.
 *  Copyright and related rights are licensed under the MIT license.
 *
 *  Noted:
 *    1) exchange information between TSN and CAN;
 *
 */

`timescale 1ns / 1ps

// `define TEST_LOOPBACK
// `define SUPPORT_MULTIPULE_PORT
`define SUPPORT_CAN

module Gateway_top(
  //* system input, clk;
   input                sys_clk_p //* 1.8v;
  ,input                sys_clk_n
  ,input                rst_n
  ,input                rst_n_button

  //* uart rx/tx from/to host;
  ,input                uart_rx    //* fpga receive data from host;
  ,output  wire         uart_tx    //* fpga send data to host;
  ,input                uart_cts
  ,output  wire         uart_rts

  //* can
//  `ifdef SUPPORT_CAN
    ,inout       [7:0]  can_ad
    ,output  wire       can_cs_n
    ,output  wire       can_ale
    ,output  wire       can_wr_n
    ,output  wire       can_rd_n
    ,input              can_int_n
    ,output  wire       can_rst_n
//  `endif

  //* sgmii port
  ,input  wire          SFP_REFCLK_P   
  ,input  wire          SFP_REFCLK_N 
  ,output wire          FX_RX_P
  ,output wire          FX_RX_N
  ,input  wire          FX_TX_P
  ,input  wire          FX_TX_N

  ,output  wire  [1:0]  INT_N_PME_N
  ,output  reg   [1:0]  RESET_N
  ,output  wire  [1:0]  MDC
);

  reg    [31:0]  phy_cnt;
  
  // assign uart_rts       = 1'b0;       //* host can send to fpga anytime;
  assign can_rst_n      = rst_n;      //* can reset_n;
  assign INT_N_PME_N[0] = 1'b1;
  assign INT_N_PME_N[1] = 1'b1;
  assign MDC[0]         = 1'b0;
  assign MDC[1]         = 1'b0;

  //* clock & locker;
  wire    clk_125m, clk_50m;   
  wire    locked;                   //* locked =1 means generating 125M clock successfully;

  //* system reset signal, low is active;
  wire    sys_rst_n;
  assign  sys_rst_n = rst_n & locked;
  
  //* gen 125M clock;
  clk_wiz_0 clk_to_125m(
    //* Clock out ports
    .clk_out1   (clk_125m   ),          //* output 125m;
    .clk_out2   (clk_50m    ),          //* output clk_50m;
    //* Status and control signals
    .reset      (!rst_n     ),          //* input reset
    .locked     (locked     ),          //* output locked
    // Clock in ports
    // .clk_in1(sys_clk)
    .clk_in1_p  (sys_clk_p  ),          //* input clk_in1_p
    .clk_in1_n  (sys_clk_n  )           //* input clk_in1_n
  );

  //* output RESET_N;
  always @(posedge clk_125m or negedge sys_rst_n) begin           
    if(~sys_rst_n) begin//reset cpld           
      RESET_N           <= 2'b0;
      phy_cnt           <= 32'b0;     
    end 
    else begin     
      if (phy_cnt > 32'h201400 )begin 
        RESET_N         <= 2'b11;       
      end                 
      else if(phy_cnt  <= 32'h201400 && phy_cnt > 32'h201000)begin      
        RESET_N         <= 2'b0;    
         phy_cnt        <= phy_cnt + 32'b1;
      end 
      else if(phy_cnt  <= 32'h201000 && phy_cnt > 32'h200000)begin      
        RESET_N         <= 2'b11;
        phy_cnt         <= phy_cnt + 32'b1;
      end                     
      else begin            
        RESET_N         <= 2'b0;            
        phy_cnt         <= phy_cnt + 32'b1;   
      end                                         
    end            
  end

  wire                  mux_pktData_valid_um;
  wire  [133:0]         mux_pktData_um;
  wire  [133:0]         pktData_gmii, pktData_um;
  wire                  pktData_valid_gmii, pktData_valid_um;
  wire  [133:0]         pktData_pe, temp_pktData_pe;
  wire                  pktData_valid_pe;
  wire                  w_to_PE_alf;
  wire  [167:0]         metaIn, metaOut;
  wire                  metaIn_valid, metaOut_valid;
  wire  [15:0]          pkt_length_gmii;
  assign                metaIn_valid    = (pktData_valid_gmii == 1'b1) & 
                                          (pktData_gmii[133:132] == 2'b10);
  assign                metaIn          = {8'h02,     //* inPort in bitmap;
                                            4'b0,(4'd1<<pktData_gmii[129:128]), //* outPort in dec;
                                            8'h01,    //* pe in bitmap;
                                            16'h1100, //* bufferID, don't care;
                                            16'h0080, //* 0080 is for dma, 0 is for dra;
                                            16'h0001, //* don't care;
                                            16'h0100, //* don't care;
                                            pkt_length_gmii,
                                            64'h1234};//* timestamp;

  soc_runtime runtime(
    .clk_125m             (clk_125m                     ),
    .sys_rst_n            (sys_rst_n                    ),
    //* sgmii input;
    .SFP_REFCLK_P         (SFP_REFCLK_P                 ),
    .SFP_REFCLK_N         (SFP_REFCLK_N                 ),
    .FX_RX_P              (FX_RX_P                      ),
    .FX_RX_N              (FX_RX_N                      ),
    .FX_TX_P              (FX_TX_P                      ),
    .FX_TX_N              (FX_TX_N                      ),
    //* um;
    .pktData_valid_gmii   (pktData_valid_gmii           ),
    .pktData_gmii         (pktData_gmii                 ),
    .pkt_length_gmii      (pkt_length_gmii              ),
    .ready_in             (1'b1                         ),
    .pktData_valid_um     (mux_pktData_valid_um         ),
    .pktData_um           (mux_pktData_um               )
  );

  
  //======================= PE_ARRAY         =====================//
  wire   [7:0]   can_ad_i,can_ad_o;
   wire           can_ad_sel;
   assign can_ad= can_ad_sel? 8'dz : can_ad_o;
   assign can_ad_i = can_ad;
  PE_ARRAY PE_ARRAY_inst(
    //* clock & resets;
    .i_sys_clk            (clk_125m                     ),
    .i_sys_rst_n          (1'b1                         ),
    .i_pe_clk             (clk_50m                      ),
    .i_rst_n              (sys_rst_n                    ),
    //* pkt from/to CPI
    //* pkt from CPI, TODO,
    .i_pe_conf_mac        (48'h8888_8888_8988           ),
    .i_data_valid         (pktData_valid_gmii           ),
    // .i_data_valid         (1'b0           ),
    .i_data               (pktData_gmii                 ),
    .i_meta_valid         (metaIn_valid                 ),
    .i_meta               (metaIn                       ),
    .o_alf                (w_to_PE_alf                  ),
    //* pkt to CPI, TODO,
    .o_data_valid         (pktData_valid_pe             ),
    .o_data               (temp_pktData_pe              ),
    .o_meta_valid         (metaOut_valid                ),
    .o_meta               (metaOut                      ),
    .i_alf                (1'b0                         ),
    //* uart;
      .i_uart_rx          (uart_rx         				      ),
      .o_uart_tx          (uart_tx         				      ),
      .i_uart_cts         (uart_cts        				      ),
      .o_uart_rts         (uart_rts        				      ),
    
    //* add CAN module's signal
    .i_can_ad            (can_ad_i),
    .o_can_ad            (can_ad_o),
    .o_can_ad_sel         (can_ad_sel),
    .o_can_cs_n           (can_cs_n),
    .o_can_ale_as         (can_ale),
    .o_can_wr_n           (can_wr_n),
    .o_can_rd_n           (can_rd_n),
    .o_can_mode           (),
    .i_can_int_n          (can_int_n),
    
    //* pads;
    .i_start_en_pad       (4'd1                         )
  );
  //==============================================================//

  Pkt_Asyn_Send Pkt_Asyn_Send(
    .i_sys_clk            (clk_125m                     ),
    .i_pe_clk             (clk_50m                      ),
    .i_rst_n              (sys_rst_n                    ),
    //* interface for recv/send pkt;
    .i_data_valid         (pktData_valid_pe             ),
    .i_data               (pktData_pe                   ),
    //* TODO
    .o_data_valid         (pktData_valid_um             ),
    .o_data               (pktData_um                   )
  );

  //* write back outport at pkt[131:128];
  `ifdef SUPPORT_MULTIPULE_PORT
    assign  pktData_pe = (metaOut_valid == 1'b0)? temp_pktData_pe:
                          {temp_pktData_pe[133:132],metaOut[163:160],temp_pktData_pe[127:0]};
  `else
    assign  pktData_pe = temp_pktData_pe;
  `endif

  `ifdef TEST_LOOPBACK
    //* test loopback;
    assign mux_pktData_valid_um = pktData_valid_gmii;
    assign mux_pktData_um       = pktData_gmii;
  `else
    //* test loopback;
    assign mux_pktData_valid_um = pktData_valid_um;
    assign mux_pktData_um       = pktData_um;
  `endif

endmodule
